#pragma once

#include <iostream>
#include <vector>
#include <unistd.h>
#include <pthread.h>
#include "Mutex.hpp"
#include "Cond.hpp"
#include "Sem.hpp"

namespace RingQueueModule
{
    using namespace MutexModule;
    using namespace CondModule;
    using namespace SemModule;

    template<class T>
    class RingQueue
    {
    public:
        RingQueue(int cap)
            :_ring(cap), _cap(cap), _p_step(0)
            ,_c_step(0), _spacesem(cap), _datasem(0)
        {}

        void Equeue(const T& data)
        {
            // 1.LockGuard lockguard(_p_lock);
            //先申请信号量，在竞争锁，效率更高
            _spacesem.P();
            LockGuard lockguard(_p_lock);
            _ring[_p_step++] = data;
            _p_step %= _cap;
            _datasem.V();
        }

        void Pop(T *out)
        {
            _datasem.P();
            LockGuard lockguard(_c_lock);
            *out = _ring[_c_step++];
            _c_step %= _cap;
            _spacesem.V();  //释放资源，信号量+1
        }

        ~RingQueue()
        {}

    private:
        std::vector<T> _ring;    //临界资源
        int _cap;                //临界空间大小
        int _p_step;             //生产者位置
        int _c_step;             //消费者位置
        Sem _spacesem;           //空间信号量
        Sem _datasem;            //数据信号量

        Mutex _p_lock;           
        Mutex _c_lock;
    };
}